package edu.washington.ling.syntric.io;

import java.util.Iterator;
import java.util.Arrays;
import java.util.regex.*;

import edu.washington.ling.syntric.struct.error.CollectingExceptionHandler;
import edu.washington.ling.syntric.struct.error.UnreadableLineException;
import edu.washington.ling.syntric.struct.error.UnreadableRepresentationException;
import edu.washington.ling.syntric.struct.tree.Token;
import edu.washington.ling.syntric.struct.tree.Tree;


public class TreeReaderLinks extends TreeReader {
	
	private static Pattern linkPattern = Pattern.compile("\\d+ \\d+ ([a-zA-Z0-9\\-]+ )?#.+");
	
	private boolean isSentLine(String line){
		return line.startsWith("sent: ");
	}
	private boolean isTagsLine(String line){
		return line.startsWith("tags: ");
	}
	private boolean isLinkLine(String line){
		return linkPattern.matcher(line).matches();
	}
	private void checkSentLineFormat(String line) throws UnreadableLineException {
		if (!isSentLine(line)) {
			throw new UnreadableLineException("misformatted sentence line", line, "sent: word1 word2 ...");
		}
	}
	private void checkTagsLineFormat(String line) throws UnreadableLineException {
		if (!isTagsLine(line)) {
			throw new UnreadableLineException("misformatted tags line", line, "tags: tag1 tag2 ...");
		}
	}
	private void checkLinkLineFormat(String line) throws UnreadableLineException {
		if (!isLinkLine(line)) {
			throw new UnreadableLineException("misformatted link line", line, "childID parentID [relType] # ...");
		}
	}
	private void readSentLine(String line, Tree tree){
		if (isSentLine(line)) {
			line = line.trim();
			String[] words = line.split("\\s");
			for (int i = 1; i < words.length; i++){
				Token t = new Token();
				t.setName(Integer.toString(i));
				t.setWord(words[i]);
				tree.addToken(t);
			}
		}
	}
	private void readTagsLine(String line, Tree tree) {
		if(isTagsLine(line)) {
			line = line.trim();
			String[] tags = line.split("\\s");
			Iterator<Token> tokens = tree.getTokenList().iterator();
			for (int i = 1; i < tags.length && tokens.hasNext(); i++) {
				Token t = tokens.next();
				t.setTag(tags[i]);
			}
		}
	}

	private void readLinkLine(String line, Tree tree) {
		if(isLinkLine(line)) {
			line = line.trim();
			line = line.replaceFirst("#.+", "");
			String[] elems = line.split("\\s");
			String childName = elems[0];
			String parentName = elems[1];
			if (childName.equals(parentName)){
				Token root = tree.getTokenWithName(parentName);
				tree.addDSRoot(root);
			}
			else {
				Token child = tree.getTokenWithName(childName);
				Token parent = tree.getTokenWithName(parentName);
				child.setDSHead(parent);
				parent.addDSDependent(child);
				if (elems.length == 3) {
					String relType = elems[2];
					child.setDSRelation(relType);
				}
			}
		}
	}
	
	public void checkRepFormat(TreeRepresentation rep) throws UnreadableRepresentationException {
		CollectingExceptionHandler cHandler = new CollectingExceptionHandler();
		String[] lines = rep.getTreeLines();
		String sentLine = lines[0];
		String tagsLine = lines[1];
		String[] linkLines = Arrays.copyOfRange(lines, 3, lines.length);
		try {
			checkSentLineFormat(sentLine);
		}
		catch(UnreadableLineException e) {
			cHandler.handle(e);
		}
		try {
			checkTagsLineFormat(tagsLine);
		}
		catch(UnreadableLineException e) {
			cHandler.handle(e);
		}
		for (String linkLine: linkLines) {
			try {
				checkLinkLineFormat(linkLine);
			} 
			catch (UnreadableLineException e) {
				cHandler.handle(e);
			}
		}
		if (cHandler.hasMessages()) {
			throw new UnreadableRepresentationException("badly formatted representation", cHandler.getMessages());
		}
	}
	public Tree readTree(TreeRepresentation tr) throws UnreadableRepresentationException {
		checkRepFormat(tr);
		Tree tree = new Tree(tr.getLayer());
		tree.setMetaData(tr.getMetaData());
		String[] lines = tr.getTreeLines();
		String sentLine = lines[0];
		String tagsLine = lines[1];
		String[] linkLines = Arrays.copyOfRange(lines, 3, lines.length);
		readSentLine(sentLine, tree);
		readTagsLine(tagsLine, tree);		
		for (String linkLine: linkLines){
			readLinkLine(linkLine, tree);
		}
		return tree;
	}
	public String getFormat() {
		return "links";
	}
}